package service

import (
	"context"
	"errors"
	"gorm.io/gorm"
	"shop-bean/constant"
	"shop-bean/model"
	"shop-common/library/variables"
	"shop-common/utils/pagehelper"
	"shop-common/utils/queryWrapper"
	"shop-service/cache"
	"shop-service/repository"
)

type IProdTagService interface {
	FindPage(ctx context.Context, req *pagehelper.SearchPageRequest) (*pagehelper.Record, error)
	CheckExist(ctx context.Context, wp *queryWrapper.WherePair) (bool, error)
	Find(ctx context.Context) (list []*model.ProdTag, err error)
	FindById(ctx context.Context, id uint) (prodTag *model.ProdTag, err error)
	Create(ctx context.Context, prodTag *model.ProdTag) error
	Updates(ctx context.Context, id uint, columns map[string]interface{}) error
	Delete(ctx context.Context, id uint) error
	FindProdTag(ctx context.Context) ([]*model.ProdTag, error)
}

type ProdTagService struct {
	db          *gorm.DB
	repository  repository.IProdTagRepository
	redisClient cache.IRedisProdTagCache
}

func NewProdTagService(repository repository.IProdTagRepository) IProdTagService {
	return &ProdTagService{variables.GormDB(), repository, cache.NewRedisProdTagCache()}
}

func (s *ProdTagService) FindPage(ctx context.Context, req *pagehelper.SearchPageRequest) (*pagehelper.Record, error) {
	paginator := pagehelper.New().SetOffset(req).SetFilter([]string{"id"}).
		IsPush(req.Keyword != "", queryWrapper.Like("title", req.Keyword)).
		IsPush(req.Status > 0, queryWrapper.Eq("status", req.Status)).Paginator()

	count, err := s.repository.Count(s.db, paginator.Params)
	if err != nil {
		variables.Logger.Errorf(ctx, "find prodTag to count failed: err %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	if count == 0 {
		return paginator.Result(nil, count)
	}

	page, err := s.repository.FindPage(s.db, paginator.Params)
	if err != nil {
		variables.Logger.Errorf(ctx, "find prodTag to page: err: %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	return paginator.Result(page, count)
}

func (s *ProdTagService) CheckExist(ctx context.Context, wp *queryWrapper.WherePair) (bool, error) {
	exist, err := s.repository.CheckExistByProdTag(s.db, wp)
	if err != nil {
		variables.Logger.Errorf(ctx, "checkExist prodTag failed: err %v, pair %+v", err, wp)
		return exist, err
	}
	return exist, nil
}

func (s *ProdTagService) Find(ctx context.Context) (list []*model.ProdTag, err error) {
	list, err = s.redisClient.GetListCache()
	if len(list) > 0 && err == nil {
		return
	}

	list, err = s.repository.Find(s.db, queryWrapper.Eq("shop_id", constant.SHOP_ID))
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		variables.Logger.Errorf(ctx, "find prodTag failed: err %v", err)
		return nil, err
	}

	_ = s.redisClient.PutListCache(list)

	return list, nil
}

func (s *ProdTagService) FindById(ctx context.Context, id uint) (prodTag *model.ProdTag, err error) {
	prodTag, err = s.repository.FindById(s.db, id)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		variables.Logger.Errorf(ctx, "findById prodTag failed: err %v, id %d", err, id)
		return nil, err
	}
	return prodTag, nil
}

func (s *ProdTagService) Create(ctx context.Context, prodTag *model.ProdTag) error {
	err := s.repository.Create(s.db, prodTag)
	if err != nil {
		variables.Logger.Errorf(ctx, "create prodTag failed: err %v, prodTag %+v", err, prodTag)
		return err
	}

	_ = s.redisClient.RemoveCache()
	return nil
}

func (s *ProdTagService) Updates(ctx context.Context, id uint, columns map[string]interface{}) error {
	if err := s.repository.Updates(s.db, id, columns); err != nil {
		variables.Logger.Errorf(ctx, "updates prodTag failed: err %v, columns %+v", err, columns)
		return err
	}

	_ = s.redisClient.RemoveCache()
	return nil
}

func (s *ProdTagService) Delete(ctx context.Context, id uint) error {
	if err := s.repository.Delete(s.db, id); err != nil {
		variables.Logger.Errorf(ctx, "delete prodTag failed: err %v, id %d", err, id)
		return err
	}

	_ = s.redisClient.RemoveCache()
	return nil
}

func (s *ProdTagService) FindProdTag(ctx context.Context) ([]*model.ProdTag, error) {
	pair := queryWrapper.Eq("status", constant.GLOBAL_ENABLE)
	prodTags, err := s.repository.Find(s.db, pair)
	if err != nil {
		variables.Logger.Errorf(ctx, "find prodTag to where status failed: err %, pair: %+v", err, pair)
		return nil, err
	}

	return prodTags, nil
}
